﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;

using Ionic.Zip;

using EdgeStatz.ModelEngine.DatabaseTools;
using EdgeStatz.ESSystems.Objects;

namespace EdgeStatz
{
    public partial class ModelInstaller : Form
    {
        public static readonly string FUNCTION_INSTALL_NEW = "INSTALL";
        public static readonly string FUNCTION_DELETE_EXISTING = "DELETE";

        private string function = FUNCTION_INSTALL_NEW;
        private int stage = 0;
        
        public ModelInstaller(string function)
        {
            if (function.Equals(FUNCTION_INSTALL_NEW))
                InitializeComponent_Installation();
            else if (function.Equals(FUNCTION_DELETE_EXISTING))
                InitializeComponent_Deletion();

            this.function = function;
            this.stage = 0;
            b_Next_Click(null, null);
        }

        #region Install

        #region Stage 1

        string savePath = null;

        private void b_Install_1_Browse_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofdialog = new OpenFileDialog();
            ofdialog.Title = "Open Zip File";
            ofdialog.Filter = "Zip|*.zip|All files|*.*";
            ofdialog.Multiselect = false;
            if (ofdialog.ShowDialog() == DialogResult.OK)
            { 
                tb_Install_1_ZipFile.Text = ofdialog.FileName;
            }
        }
        
        private void b_Install_1_Folder_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog fbdialog = new FolderBrowserDialog();
            fbdialog.Description = "Save Model Data";
            fbdialog.ShowNewFolderButton = true;
            fbdialog.SelectedPath = tb_Install_1_SaveFolder.Text;

            if (fbdialog.ShowDialog() == DialogResult.OK)
            {
                tb_Install_1_SaveFolder.Text = fbdialog.SelectedPath;
            }
        }

        private bool Install_Complete_Stage_1()
        {
            prog_Install_Zip.Value = 0;
            if (!File.Exists(tb_Install_1_ZipFile.Text))
            { MessageBox.Show("The zip file selected could not be found."); return false; }
            if (tb_Install_1_SaveFolder.Text.Trim().Equals(""))
            { MessageBox.Show("The save folder cannot be empty."); return false; }
            prog_Install_Zip.Value = 10;
            using (ZipFile zip1 = ZipFile.Read(tb_Install_1_ZipFile.Text))
            {
                FileInfo zip = new FileInfo(zip1.Name);
                this.savePath = tb_Install_1_SaveFolder.Text + "\\" + zip.Name.Substring(0, zip.Name.Length - zip.Extension.Length);
                int i = 1;
                while (Directory.Exists(this.savePath))
                { this.savePath = tb_Install_1_SaveFolder.Text + "\\" + zip.Name.Substring(0, zip.Name.Length - zip.Extension.Length) + " (" + i + ")"; i++; }
                Directory.CreateDirectory(this.savePath);
                prog_Install_Zip.Value = 20;
                if (!tb_Install_1_ZipPass.Text.Equals(""))
                    zip1.Password = tb_Install_1_ZipPass.Text;
                try
                {
                    zip1.ExtractAll(savePath, ExtractExistingFileAction.OverwriteSilently);
                }
                catch (Exception e)
                {
                    MessageBox.Show("Extraction has failed:\n" + e.GetType().Name + ":\n" + e.Message, "Extraction Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return false;
                }
                finally
                {
                    prog_Install_Zip.Value = 100;
                }
            }
            return true;
        }
        #endregion

        #region Stage 2

        string modelPath = null;
        DBStructureEngine databaseEngine = null;

        public string ModelPath
        {
            get { return modelPath; }
        }

        private bool Install_Load_Stage_2()
        {
            if (this.savePath == null)
            {
                MessageBox.Show("An Error has occured: The path the zip file was extracted to cannot be found.",
                  "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return false;
            }
            modelPath = Find_Model_File(savePath);
            if (modelPath == null)
            {
                MessageBox.Show("An EdgeStatz Model file (.esm) could not be found within the  extracted files.\n" +
                "Please select the model file.", "File Not Found", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                OpenFileDialog ofdialog = new OpenFileDialog();
                ofdialog.Title = "Open Model File";
                ofdialog.Filter = "EdgeStatz Model|*.esm|XML|*.xml|All files|*.*";
                ofdialog.Multiselect = false;
                if (ofdialog.ShowDialog() == DialogResult.OK)
                {
                    modelPath = ofdialog.FileName;
                }
                else
                {
                    return false;
                }
            }
            databaseEngine = new DBStructureEngine(modelPath);
            databaseEngine.ModelPath = new FileInfo(modelPath).Directory.FullName;
            tb_Install_2_ModelName.Text = databaseEngine.ModelName;
            tb_Install_2_DbName.Text = databaseEngine.DatabaseName;
            tb_Install_2_DbPath.Text = databaseEngine.DatabasePath;
            Provider def_provider = databaseEngine.GetDefaultProvider();
            if (def_provider != null)
            {
                tb_Install_2_Server.Text = def_provider.Server;
                tb_Install_2_Uid.Text = def_provider.UserId;
                tb_Install_2_Pwd.Text = def_provider.Password;
            }
            return true;
        }

        private string Find_Model_File(string path)
        {
            DirectoryInfo dir = new DirectoryInfo(path);
            FileInfo[] fileList = dir.GetFiles();
            DirectoryInfo[] dirList = dir.GetDirectories();
            foreach (FileInfo file in fileList)
            {
                if (file.Extension.ToLower().Equals(".esm"))
                { return file.FullName; }
            }
            for (int i = 0; i < dirList.Length; i++)
            {
                string tmp_path = Find_Model_File(dirList[i].FullName);
                if (tmp_path != null)
                    return tmp_path;
            }
            return null;
        }

        void b_Install_2_Folder_Click(object sender, System.EventArgs e)
        {
            FolderBrowserDialog fbdialog = new FolderBrowserDialog();
            fbdialog.Description = "Save Db Data";
            fbdialog.ShowNewFolderButton = true;
            fbdialog.SelectedPath = tb_Install_2_DbPath.Text;

            if (fbdialog.ShowDialog() == DialogResult.OK)
                tb_Install_2_DbPath.Text = fbdialog.SelectedPath;
        }

        private bool Install_Complete_Stage_2() 
        {
            if (tb_Install_2_ModelName.Text.Trim().Equals(""))
            { MessageBox.Show("Model Name cannot be empty."); return false; }
            if (tb_Install_2_DbName.Text.Trim().Equals(""))
            { MessageBox.Show("Database Name cannot be empty."); return false; }
            if (tb_Install_2_DbPath.Text.Trim().Equals(""))
            { MessageBox.Show("Database save path cannot be empty."); return false; }
            if (tb_Install_2_Server.Text.Trim().Equals(""))
            { MessageBox.Show("Server Name cannot be empty."); return false; }

            this.databaseEngine.ModelName = tb_Install_2_ModelName.Text;
            this.databaseEngine.DatabaseName = tb_Install_2_DbName.Text;
            this.databaseEngine.DatabasePath = tb_Install_2_DbPath.Text;
            Provider prov = new Provider("Default", tb_Install_2_Server.Text, this.databaseEngine.DatabaseName, 
                tb_Install_2_Uid.Text, tb_Install_2_Pwd.Text, true);
            if(!GlobalObjectsSQL.TestConnection(prov))
            { MessageBox.Show("Connection to database server {" + prov.Server + "} has failed.", 
                "Connection Failed", MessageBoxButtons.OK, MessageBoxIcon.Error); return false;}
            
            if(cb_Install_2_Default.Checked)
                this.databaseEngine.SetProviders(new Provider[] { prov });

            this.databaseEngine.SaveChanges();
            GlobalObjectsSQL.SetConnectionString(prov);
            try
            {
                this.databaseEngine.UpdateDatabaseAgainstModel();
            }
            catch (Exception e)
            {
                MessageBox.Show("An " + e.GetType().Name + " occured while updating database.\n\n" + e.Message,
                    "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
            return true;
        }
        #endregion

        #region Stage 3
        private TableData[] importTables = null;
        public TableData[] ImportTables
        { get { return importTables; } }

        void b_Install_3_DataFile_Click(object sender, System.EventArgs e)
        {
            OpenFileDialog ofdialog = new OpenFileDialog();
            ofdialog.Title = "Import Data";
            ofdialog.Filter = "EdgeStatz Data|*.esd|XML|*.xml|All files|*.*";
            ofdialog.Multiselect = false;
            if (ofdialog.ShowDialog() == DialogResult.OK)
                tb_Install_3_DataFile.Text = ofdialog.FileName;
        }
        private bool Install_Complete_Stage_3() 
        {
            if (!tb_Install_3_DataFile.Text.Trim().Equals(""))
                importTables = DataEngine.Import(tb_Install_3_DataFile.Text);
            else
                importTables = null;
            return true; 
        }

        #endregion

        #endregion

        #region Delete

        #region Stage 1

        private void rb_Delete_1_UseReg_CheckedChanged(object sender, EventArgs e)
        {
            if (rb_Delete_1_UseReg.Checked)
            {
                cb_Delete_1_RegModels.Enabled = true;
                tb_Delete_1_File.Enabled = false;
                rb_Delete_1_UseFile.Checked = false;
                b_Delete_1_Browse.Enabled = false;
            }
        }

        private void rb_Delete_1_UseFile_CheckedChanged(object sender, EventArgs e)
        {
            if (rb_Delete_1_UseFile.Checked)
            {
                tb_Delete_1_File.Enabled = true;
                b_Delete_1_Browse.Enabled = true;
                cb_Delete_1_RegModels.Enabled = false;
                rb_Delete_1_UseReg.Checked = false;                
            }
        }

        void b_Delete_1_Browse_Click(object sender, System.EventArgs e)
        {
            OpenFileDialog ofdialog = new OpenFileDialog();
            ofdialog.Title = "Open Model File";
            ofdialog.Filter = "EdgeStatz Model|*.esm|XML|*.xml|All files|*.*";
            ofdialog.Multiselect = false;
            if (ofdialog.ShowDialog() == DialogResult.OK)
                tb_Delete_1_File.Text = ofdialog.FileName;
        }

        private bool Delete_Load_Stage_1() 
        {
            if (GlobalRegistrySettings.ModelCount > 0)
            {
                rb_Delete_1_UseReg.Checked = true;
                DisplayValueObject[] dvObjs = new DisplayValueObject[GlobalRegistrySettings.ModelCount];
                string[] names = GlobalRegistrySettings.ModelNames;
                string[] paths = GlobalRegistrySettings.ModelPaths;
                for (int i = 0; i < GlobalRegistrySettings.ModelCount; i++)
                    dvObjs[i] = new DisplayValueObject(names[i], paths[i]);

                cb_Delete_1_RegModels.DataSource = dvObjs;
                cb_Delete_1_RegModels.DisplayMember = "Display";
                cb_Delete_1_RegModels.ValueMember = "Value";
            }
            else
            {
                rb_Delete_1_UseFile.Checked = true;
            }
            return true; 
        }

        private bool Delete_Complete_Stage_1() 
        {
            if ((rb_Delete_1_UseReg.Checked && cb_Delete_1_RegModels.SelectedItem == null) || 
                (rb_Delete_1_UseFile.Checked && tb_Delete_1_File.Text.Trim().Equals("")))
            { MessageBox.Show("A Model must be selected from the before continuing.", "Error", 
                MessageBoxButtons.OK, MessageBoxIcon.Error); return false; }

            if (rb_Delete_1_UseReg.Checked)
            {
                modelPath = ((DisplayValueObject)cb_Delete_1_RegModels.SelectedItem).Value;
            }
            else if (rb_Delete_1_UseFile.Checked)
            {
                modelPath = tb_Delete_1_File.Text;
            }
            else
                return false;
            return true; 
        }
        #endregion
        
        #region Stage 2

        bool[] toDel = null;

        void cb_Delete_2_All_CheckedChanged(object sender, System.EventArgs e)
        {
            if (cb_Delete_2_All.Checked)
            {
                cb_Delete_2_Db.Checked = true;
                cb_Delete_2_Logs.Checked = true;
                cb_Delete_2_Reg.Checked = true;
                cb_Delete_2_Files.Checked = true;
                cb_Delete_2_Model.Checked = true;
            }
        }

        void cb_Delete_2_Files_CheckedChanged(object sender, System.EventArgs e)
        {
            if (cb_Delete_2_Files.Checked)
            {
                cb_Delete_2_Logs.Checked = true;
                cb_Delete_2_Logs.Enabled = false;
                cb_Delete_2_Model.Checked = true;
                cb_Delete_2_Model.Enabled = false;
            }
            else
            {
                cb_Delete_2_Logs.Enabled = true;
                cb_Delete_2_Model.Enabled = true;
            }
        }

        private bool Delete_Load_Stage_2() 
        {
            if (modelPath != null)
                return true;
            else
                return false;
        }

        private bool Delete_Complete_Stage_2() 
        {
            if (!cb_Delete_2_Db.Checked && !cb_Delete_2_Logs.Checked && !cb_Delete_2_Reg.Checked &&
                !cb_Delete_2_Files.Checked && !cb_Delete_2_Model.Checked)
            { MessageBox.Show("At least one of the components must be selected.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; }

            toDel = new bool[] { cb_Delete_2_Db.Checked, cb_Delete_2_Reg.Checked, cb_Delete_2_Files.Checked, cb_Delete_2_Logs.Checked, cb_Delete_2_Model.Checked };
            return true; 
        }
        
        #endregion
        
        #region Stage 3

        private void cb_Delete_3_Export_CheckedChanged(object sender, EventArgs e)
        {
            if (cb_Delete_3_Export.Checked)
            {
                tb_Delete_3_File.Enabled = false;
                b_Delete_3_Save.Enabled = false;
            }
            else
            {
                tb_Delete_3_File.Enabled = false;
                b_Delete_3_Save.Enabled = false;
            }
        }

        private void b_Delete_3_Save_Click(object sender, EventArgs e)
        {
            SaveFileDialog sfdialog = new SaveFileDialog();
            sfdialog.Title = "Save Data Dialog";
            sfdialog.Filter = "EdgeStatz Data|*.esd|XML|*.xml|All files|*.*";
            sfdialog.DefaultExt = "xml";
            if (sfdialog.ShowDialog() == DialogResult.OK)
                tb_Delete_3_File.Text = sfdialog.FileName;
        }

        private bool Delete_Load_Stage_3() 
        {
            if (toDel != null)
                return true;
            else
                return false;
        }

        private bool Delete_Complete_Stage_3() 
        {
            if (cb_Delete_3_Export.Checked && tb_Delete_3_File.Text.Trim().Equals(""))
            { MessageBox.Show("Please select a file location for the export data","Error",MessageBoxButtons.OK,MessageBoxIcon.Error); return false; }

            if (cb_Delete_3_Export.Checked) 
            { /* Do Data Export */}

            prog_Delete_3.Value = 0;
            databaseEngine = new DBStructureEngine(modelPath);
            if (toDel[0]) // Database
                databaseEngine.DeleteDatabase();
            prog_Delete_3.Value = 20;
            if (toDel[1]) // Registry
            {
                try { GlobalRegistrySettings.DeleteModelKey(databaseEngine.ModelName); }
                catch (Exception e)
                { MessageBox.Show("Registry key delete failed.\n" + e.GetType().Name + "\n" + e.Message); };
            }
            prog_Delete_3.Value = 40;
            if (toDel[2] || toDel[3] || toDel[4]) // Files
            {
                try 
                {
                    if (toDel[2]) // All Files
                        new DirectoryInfo(databaseEngine.ModelPath).Delete(true);
                    else
                    {
                        if (toDel[3]) // Logs
                            new DirectoryInfo(databaseEngine.ModelPath).Delete(true);
                        if (toDel[4]) // Model File
                        { File.Delete(modelPath); }
                    }
                }
                catch (Exception e)
                {
                    MessageBox.Show("An Error has occured while deleting the files:\n" + e.GetType().Name +
                        "\n" + e.Message, "Error deleting files", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                prog_Delete_3.Value = 60;
            }
            
            prog_Delete_3.Value = 100;
            return true; 
        }
        
        #endregion

        #endregion

        #region Wizard Controls

        private void b_Next_Click(object sender, EventArgs e)
        {
            if (function.Equals(FUNCTION_INSTALL_NEW)) 
            {
                switch (stage)
                {
                    case 0:
                        this.stage++;
                        this.p_body.Controls.Clear();
                        this.p_body.Controls.Add(this.p_Install_1);
                        this.b_Next.Enabled = true;
                        this.b_Finish.Enabled = false;
                        break;
                    case 1:
                        if (Install_Complete_Stage_1() && Install_Load_Stage_2())
                        {
                            this.stage++;
                            this.p_body.Controls.Clear();
                            this.p_body.Controls.Add(this.p_Install_2);
                            this.b_Next.Enabled = true;
                            this.b_Finish.Enabled = true;
                        }
                        break;
                    case 2:
                        if (Install_Complete_Stage_2())
                        {
                            this.stage++;
                            this.p_body.Controls.Clear();
                            this.p_body.Controls.Add(this.p_Install_3);
                            this.b_Next.Enabled = false;
                            this.b_Finish.Enabled = true;
                        }
                        break;
                }
            }
            else if (function.Equals(FUNCTION_DELETE_EXISTING)) 
            {
                switch (stage)
                {
                    case 0:
                        if (Delete_Load_Stage_1())
                        {
                            this.stage++;
                            this.p_body.Controls.Clear();
                            this.p_body.Controls.Add(this.p_Delete_1);
                            this.b_Next.Enabled = true;
                            this.b_Finish.Enabled = false;
                        }
                        break;
                    case 1:
                        if (Delete_Complete_Stage_1() && Delete_Load_Stage_2())
                        {
                            this.stage++;
                            this.p_body.Controls.Clear();
                            this.p_body.Controls.Add(this.p_Delete_2);
                            this.b_Next.Enabled = true;
                            this.b_Finish.Enabled = true;
                        }
                        break;
                    case 2:
                        if (Delete_Complete_Stage_2() && Delete_Load_Stage_3())
                        {
                            this.stage++;
                            this.p_body.Controls.Clear();
                            this.p_body.Controls.Add(this.p_Delete_3);
                            this.b_Next.Enabled = false;
                            this.b_Finish.Enabled = true;
                        }
                        break;
                }
            }            
        }

        private void b_Finish_Click(object sender, EventArgs e)
        {
            if (function.Equals(FUNCTION_INSTALL_NEW))
            {
                switch (stage)
                {
                    case 2:
                        if (Install_Complete_Stage_2())
                        {
                            this.DialogResult = DialogResult.OK;
                            this.Close();
                        }
                        break;
                    case 3:
                        if (Install_Complete_Stage_3())
                        {
                            this.DialogResult = DialogResult.OK;
                            this.Close();
                        }
                        break;
                }
            }
            else if (function.Equals(FUNCTION_DELETE_EXISTING)) 
            {
                switch (stage)
                {
                    case 2:
                        if (Delete_Complete_Stage_2() && Delete_Complete_Stage_3())
                        {
                            this.DialogResult = DialogResult.OK;
                            this.Close();
                        }
                        break;
                    case 3:
                        if (Delete_Complete_Stage_3())
                        {
                            this.DialogResult = DialogResult.OK;
                            this.Close();
                        }
                        break;
                }
            }    
        }

        private void b_Cancel_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.Abort;
            this.Close();
        }
        
        #endregion




    }
}
